// -----------------------------------------------------------------------------
// This source file is part of Matrix Platform
// 	(Universal .NET Software Development Platform)
// For the latest info, see http://www.matrixplatform.com
// 
// Copyright (c) 2009-2010, Ingenious Ltd
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using Matrix.Common.Core;
using Matrix.Common.Extended;
using Matrix.Common.Extended.ThreadPools;

namespace Matrix.Framework.TestFramework
{
    /// <summary>
    /// Class manages the execution of tests.
    /// </summary>
    public class TestManager
    {
        Thread _thread = null;

        FormTesting _form;

        List<SpeedTest> _speedTests = new List<SpeedTest>();
        public List<SpeedTest> SpeedTests
        {
            get { return _speedTests; }
        }

        List<MultiThreadTest> _mutliThreadTests = new List<MultiThreadTest>();
        public List<MultiThreadTest> MutliThreadTests
        {
            get { return _mutliThreadTests; }
        }

        Dictionary<string, List<Test>> _combinedTests = new Dictionary<string, List<Test>>();

        public Dictionary<string, List<Test>> CombinedTests
        {
            get { return _combinedTests; }
        }

        public delegate void TestUpdateDelegate(TestManager manager);
        public event TestUpdateDelegate TestFinishedEvent;

        /// <summary>
        /// Constructor.
        /// </summary>
        public TestManager(FormTesting form)
        {
            _form = form;
            
            _speedTests = ReflectionHelper.GetTypeChildrenInstances<SpeedTest>(ReflectionHelper.GetAssemblies(true, true));
            _mutliThreadTests = ReflectionHelper.GetTypeChildrenInstances<MultiThreadTest>(ReflectionHelper.GetAssemblies(true, true));

            
            foreach(Test test in _speedTests)
            {
                CombinedTestAttribute attribute = ReflectionHelper.GetTypeCustomAttributeInstance<CombinedTestAttribute>(test.GetType(), true);

                if (attribute != null)
                {
                    if (_combinedTests.ContainsKey(attribute.CombinedTestName) == false)
                    {
                        _combinedTests.Add(attribute.CombinedTestName, new List<Test>());
                    }

                    _combinedTests[attribute.CombinedTestName].Add(test);
                }
            }
        }

        /// <summary>
        /// Event set speed.
        /// </summary>
        public void RunSpeedTest(SpeedTest test, int testCount)
        {
            if (_thread != null)
            {
                return;
            }

            GeneralHelper.DefaultDelegate delegateInstance = delegate()
                                                                 {
                                                                     try
                                                                     {
                                                                         Stopwatch sw = new Stopwatch();

                                                                         // Take a pre start breath.
                                                                         Thread.Sleep(100);

                                                                         sw.Start();

                                                                         bool result = test.Run(_form, testCount);

                                                                         sw.Stop();

                                                                         double perSecond = (((double)1000 / sw.ElapsedMilliseconds) * (double)testCount);
                                                                         _form.ReportMain("Test complete, time [" + sw.ElapsedMilliseconds + "] ms, rate [" + perSecond.ToString("### ### ###.") + "] / sec");

                                                                         test.OnTestFinished(_form);
                                                                     }
                                                                     catch (Exception ex)
                                                                     {
                                                                         _form.ReportMain("*EXCEPTION*:" + ex.Message);
                                                                     }
                                                                     finally
                                                                     {
                                                                         _thread = null;
                                                                     }

                                                                     if (TestFinishedEvent != null)
                                                                     {
                                                                         TestFinishedEvent(this);
                                                                     }
                                                                 };

            _thread = new Thread(new ThreadStart(delegateInstance));
            _thread.Start();
        }

        public void RunMultiThreadTest(MultiThreadTest test, TimeSpan timespan, int threadsCount)
        {
            if (_thread != null)
            {
                return;
            }

            GeneralHelper.DefaultDelegate delegateInstance = delegate()
                                                                 {
                                                                     try
                                                                     {
                                                                         bool result = test.Run(_form, threadsCount, timespan);

                                                                         double perSecond = (((double)1000 / timespan.TotalMilliseconds) * (double)test.StepsPerformed);
                                                                         _form.ReportMain("Test completed, result [" + result + "] for [" + test.StepsPerformed.ToString("### ### ### ###.") + "] items at a rate of [" + perSecond.ToString("### ### ###.") + "] / sec");

                                                                     }
                                                                     catch (Exception ex)
                                                                     {
                                                                         _form.ReportMain("*EXCEPTION*:" + ex.Message);
                                                                     }
                                                                     finally
                                                                     {
                                                                         _thread = null;
                                                                     }

                                                                     if (TestFinishedEvent != null)
                                                                     {
                                                                         TestFinishedEvent(this);
                                                                     }
                                                                 };

            _thread = new Thread(new ThreadStart(delegateInstance));
            _thread.Start();
        }

        public void Stop()
        {
            if (_thread != null)
            {
                _thread.Interrupt();

                if (_thread.ThreadState == System.Threading.ThreadState.Running
                    || _thread.ThreadState == System.Threading.ThreadState.WaitSleepJoin)
                {
                    ThreadPoolFast.StopThread(_thread, false, 50, 50);
                }
            }
            
        }
    }
}
